﻿namespace winS.Unity
{
    /// <summary>
    /// 正态分布随机器
    /// </summary>
    public class NormalDistribution
    {
        private const float max = 3.4426f;
        private const float min = -max;
        private const float width = max - min;

        /// <summary>
        /// 随机一个 [0,1] 且符合标准正态分布的 <see cref="float"/> 值
        /// </summary>
        public float Float01()
        {
            return (GetNormalDistributionnValue() - min) / width;
        }

        /// <summary>
        /// 随机一个值域为 [0, <paramref name="maxValue"/>] 且符合标准正态分布的 <see cref="float"/> 值
        /// </summary>
        public float Float(float maxValue)
        {
            return (GetNormalDistributionnValue() - min) / width * maxValue;
        }
        /// <summary>
        /// 随机一个值域为 [<paramref name="minValue"/>, <paramref name="maxValue"/>] 且符合标准正态分布的 <see cref="float"/> 值
        /// </summary>
        public float Float(float minValue, float maxValue)
        {
            return minValue + (GetNormalDistributionnValue() - min) / width * (maxValue - minValue);
        }
        /// <summary>
        /// 随机一个值域为 [-1,1] 且符合标准正态分布的 <see cref="float"/> 值
        /// </summary>
        public float FloatNormalized()
        {
            return (GetNormalDistributionnValue() - min) / width * 2f - 1f;
        }

        private float GetNormalDistributionnValue()
        {
        //使用Box–Muller算法
        //参考 https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
        Continue:
            float result = Math.Sqrt(-2f * Math.LogE(Math.Max(0.000001f, Random.Float01()))) * Math.Sin(Math.pi2 * Random.Float01());
            if (!Math.Clamp(ref result, min, max)) return result;//由于人为截断的值域并不是100%覆盖标准高斯函数,所以 result 可能超出 [min, max], 在这种情况下, 我们再来一次
            goto Continue;
        }
    }
}